summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Beck <wolfgang.beck@nokia.com>2012-04-27 12:25:03 +1000
committerWolfgang Beck <wolfgang.beck@nokia.com>2012-04-30 07:24:24 +0200
commit73382e5229b90220a1be3de30df93b42d977c148 (patch)
tree8653b6ee51e27990f33e4f7b061a4670bb1dd3e1
parent27bf83ee9a211154eb88494ee3e7810d953020f8 (diff)
Ensure Filewatcher is created on the Application thread.
Change-Id: I6e8a41408801103c2013e3e30adf83f4f3d6bb93 Reviewed-by: Lincoln Ramsay <lincoln.ramsay@nokia.com>
-rw-r--r--src/logger/qlogger.cpp45
-rw-r--r--src/logger/qlogger_p.h17
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/loggerenvar/loggerenvar.pro7
-rw-r--r--tests/auto/loggerenvar/tst_qloggerenvar.cpp258
5 files changed, 317 insertions, 13 deletions
diff --git a/src/logger/qlogger.cpp b/src/logger/qlogger.cpp
index 539c523..655fd3e 100644
--- a/src/logger/qlogger.cpp
+++ b/src/logger/qlogger.cpp
@@ -47,6 +47,8 @@
#include <QStandardPaths>
#include <QBuffer>
#include <QFileSystemWatcher>
+#include <QThread>
+#include <QCoreApplication>
#include "qlogger_p.h"
QT_USE_NAMESPACE
@@ -115,13 +117,15 @@ namespace QLoggingCategories
bool isEnabled()
{
- if (gEnvironment == EnvironmentNotChecked) checkEnvironment();
+ if (gEnvironment == EnvironmentNotChecked)
+ checkEnvironment();
return gEnabled;
}
bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type)
{
- if (!isEnabled()) return false;
+ if (!isEnabled())
+ return false;
return qLogging()->isEnabled(category, type);
}
@@ -221,14 +225,25 @@ void qSetLoggingRules(const QByteArray &rules)
+/*!
+ \internal For Autotest
+ */
+QLoggingPrivate *qtLoggerInstance()
+{
+ return qLogging();
+}
/*!
\internal
QLoggingPrivate constructor
*/
QLoggingPrivate::QLoggingPrivate()
- : _configFileWatcher(0)
+ : QObject(0)
+ , _configFileWatcher(0)
{
+ //Move object to the application thread
+ this->moveToThread(QCoreApplication::instance()->thread());
+
//add default category
_registeredCategories.append(&QLoggingCategories::default_QLoggingCategory);
}
@@ -269,17 +284,28 @@ void QLoggingPrivate::setLoggingRulesFile(const QString &path)
//Create filewatcher only if a config file exists
if (!_configFileWatcher) {
- _configFileWatcher = new QFileSystemWatcher(this);
- connect(_configFileWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
+ //This function can be called from a different thread.
+ //The creation of the filewatcher needs to be in the application thread.
+ //So we invoke the function that creates the filewatcher
+ QMetaObject::invokeMethod(this, "createFileWatcher");
}
+ QFile cfgfile(_configFile);
+ readSettings(cfgfile);
+}
+
+/*!
+ \internal
+ Invokable function to create the System File Watcher on the applicationthread.
+*/
+void QLoggingPrivate::createFileWatcher()
+{
+ _configFileWatcher = new QFileSystemWatcher(this);
+ connect(_configFileWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
QStringList oldfiles = _configFileWatcher->files();
if (!oldfiles.isEmpty())
_configFileWatcher->removePaths(oldfiles);
_configFileWatcher->addPath(_configFile);
-
- QFile cfgfile(_configFile);
- readSettings(cfgfile);
}
/*!
@@ -348,6 +374,9 @@ void QLoggingPrivate::readSettings(QIODevice &device)
gEnabled = true;
}
+#ifdef QT_BUILD_INTERNAL
+ emit configurationChanged();
+#endif
}
/*!
diff --git a/src/logger/qlogger_p.h b/src/logger/qlogger_p.h
index 7f18b9b..af91e46 100644
--- a/src/logger/qlogger_p.h
+++ b/src/logger/qlogger_p.h
@@ -81,14 +81,20 @@ public:
void setLoggingRules(const QByteArray &configcontent);
bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type);
-private slots:
- void fileChanged(const QString &path);
+ Q_INVOKABLE void createFileWatcher();
-private:
void readSettings(QIODevice &device);
void updateCategory(QLoggingCategories::QLoggingCategory *log);
-private:
+#ifdef QT_BUILD_INTERNAL
+Q_SIGNALS:
+ void configurationChanged();
+#endif
+
+public slots:
+ void fileChanged(const QString &path);
+
+public:
QFileSystemWatcher *_configFileWatcher;
QList<QLoggingCategories::QLoggingCategory *> _registeredCategories;
QString _configFile;
@@ -96,6 +102,9 @@ private:
QList<QLogConfigFilterItem> _logConfigItemList;
};
+Q_AUTOTEST_EXPORT QLoggingPrivate *qtLoggerInstance();
+
+
QT_END_HEADER
QT_LOGGER_END_NAMESPACE
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 8cda6e3..147aee7 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
SUBDIRS += \
- logger
+ logger \
+ loggerenvar
diff --git a/tests/auto/loggerenvar/loggerenvar.pro b/tests/auto/loggerenvar/loggerenvar.pro
new file mode 100644
index 0000000..3d8c8a2
--- /dev/null
+++ b/tests/auto/loggerenvar/loggerenvar.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+TARGET = loggerenvar
+
+CONFIG += testcase
+QT = core testlib logger-private
+
+SOURCES += tst_qloggerenvar.cpp
diff --git a/tests/auto/loggerenvar/tst_qloggerenvar.cpp b/tests/auto/loggerenvar/tst_qloggerenvar.cpp
new file mode 100644
index 0000000..668ce3a
--- /dev/null
+++ b/tests/auto/loggerenvar/tst_qloggerenvar.cpp
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtLogger/QtLogger>
+#include <private/qlogger_p.h>
+#include <QtTest/QtTest>
+#include <QFile>
+#include <QMutexLocker>
+#include <QtCore/qlogging.h>
+
+// redefine qDebug & Co because we don't want to use QtLogger if test application starts up.
+#if defined(qDebug)
+# undef qDebug
+#endif
+#define qDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug
+#if defined(qWarning)
+# undef qWarning
+#endif
+#define qWarning QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning
+#if defined(qCritical)
+# undef qCritical
+#endif
+#define qCritical QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical
+
+
+QT_LOG_CATEGORY(My_Category_A, "My.Category.A")
+QT_LOG_CATEGORY(My_Category_B, "My.Category.B")
+QT_LOG_CATEGORY(My_Category_C, "My.Category.C")
+#define LOGRULEFILE "./myLogRules.txt"
+
+QT_USE_NAMESPACE
+
+QMessageHandler oldMessageHandler;
+bool logReceived = false;
+QMutex threadmutex;
+
+QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context,
+ const char *str)
+{
+ QByteArray message;
+ {
+ message.append(str);
+ message.append('\n');
+ }
+
+ return message;
+}
+
+static void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg)
+{
+ QMutexLocker locker(&threadmutex);
+ QString logmsg = qMyMessageFormatString(type, context, msg);
+ if (logmsg.indexOf("My_Category") >= 0) {
+ logReceived = true;
+ }
+ else
+ oldMessageHandler(type, context, msg);
+}
+
+class LogRules
+{
+public:
+ LogRules()
+ {
+ }
+
+ void addKey(const QString &key, bool val){
+ //old key values gets updated
+ _values.insert(key, (val ? "true" : "false"));
+ if (!_configitemEntryOrder.contains(key))
+ _configitemEntryOrder.append(key);
+ }
+
+ QByteArray array()
+ {
+ QString ret;
+ QTextStream out(&ret);
+ for (int a = 0; a < _configitemEntryOrder.count(); a++) {
+ out << _configitemEntryOrder[a] << " = " << _values.value(_configitemEntryOrder[a]) << endl;
+ }
+ out.flush();
+ return ret.toLatin1();
+ }
+
+ void clear()
+ {
+ _values.clear();
+ _configitemEntryOrder.clear();
+ }
+
+private:
+ QMap<QString, QString> _values;
+ QStringList _configitemEntryOrder;
+};
+
+class LogThread : public QThread
+{
+public:
+ LogThread() {}
+
+protected:
+ void run();
+};
+
+void LogThread::run()
+{
+ qCDebug(My_Category_A) << "My_Category_A";
+ qCDebug(My_Category_B) << "My_Category_B";
+ qCDebug(My_Category_C) << "My_Category_C";
+
+ qCWarning(My_Category_A) << "My_Category_A";
+ qCWarning(My_Category_B) << "My_Category_B";
+ qCWarning(My_Category_C) << "My_Category_C";
+
+ qCCritical(My_Category_A) << "My_Category_A";
+ qCCritical(My_Category_B) << "My_Category_B";
+ qCCritical(My_Category_C) << "My_Category_C";
+}
+
+LogRules logRules;
+
+class WriteFileThread : public QThread
+{
+public:
+ WriteFileThread()
+ {}
+
+protected:
+ void run()
+ {
+ if (QFile::exists(LOGRULEFILE))
+ QFile::remove(LOGRULEFILE);
+ QFile file(LOGRULEFILE);
+ if (file.open(QIODevice::WriteOnly))
+ file.write(logRules.array());
+ }
+};
+
+class tst_QLogger : public QObject
+{
+ Q_OBJECT
+
+private:
+ QStringList logEntries;
+
+private slots:
+ void initTestCase()
+ {
+ oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler);
+
+ //prepare for testcase log with NOT callin qSetLoggingRules & Co
+ //Only the QT_LOGGING_CONFIG environment variable should activate the logging
+ //qDebug & co are redefined to avoid creating the QLogger private instance uncontrolled.
+ QByteArray ba;
+ ba.append(LOGRULEFILE);
+ qputenv("QT_LOGGING_CONFIG", ba);
+
+ //create log rules
+ logRules.addKey("My.Category.*", true);
+ pFileWriter = new WriteFileThread();
+ writeLogRuleFile();
+ //Make sure the rule file exists otherwise QtLogger will not be active
+ QTRY_VERIFY(QFile::exists(LOGRULEFILE));
+ }
+
+ void createQtLoggerFromThread()
+ {
+ logReceived = false;
+ LogThread thread;
+
+ //QtLogger private was created not in the main thread.
+ thread.start();
+ thread.wait();
+ //Make sure that message handler was called => logger private instance is created
+ QTRY_VERIFY(logReceived);
+ }
+
+ void checkFileWatcherTrigger()
+ {
+ //Now logger exist
+ QLoggingPrivate *logger = qtLoggerInstance();
+ QTRY_VERIFY(logger->_configFileWatcher);
+
+ //Check filewriter trigger
+ QSignalSpy spy(logger, SIGNAL(configurationChanged()));
+ logRules.addKey("My.Category.*", false);
+ pFileWriter = new WriteFileThread();
+ writeLogRuleFile();
+ QTRY_VERIFY(spy.count() > 0);
+
+ //Check filewriter trigger again
+ spy.clear();
+ logRules.addKey("My.Category.*", true);
+ pFileWriter = new WriteFileThread();
+ writeLogRuleFile();
+ QTRY_VERIFY(spy.count() > 0);
+ }
+
+ void cleanupTestCase()
+ {
+ qInstallMessageHandler(oldMessageHandler);
+ if (QFile::exists(LOGRULEFILE))
+ QFile::remove(LOGRULEFILE);
+ delete pFileWriter;
+ }
+
+private:
+ void writeLogRuleFile()
+ {
+ pFileWriter->start();
+ pFileWriter->wait();
+ }
+
+ WriteFileThread *pFileWriter;
+};
+
+
+QTEST_MAIN(tst_QLogger)
+#include "tst_qloggerenvar.moc"